import nls
import json
import os
import time
import threading
import logging

#! /usr/bin/env python
# coding=utf-8
import os
import time
import json
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest

# 创建AcsClient实例
client = AcsClient(
   os.getenv('ALIYUN_AK_ID'),
   os.getenv('ALIYUN_AK_SECRET'),
   "cn-shanghai"
)

# 创建request，并设置参数。
request = CommonRequest()
request.set_method('POST')
request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
request.set_version('2019-02-28')
request.set_action_name('CreateToken')

try: 
   response = client.do_action_with_exception(request)
   print(response)

   jss = json.loads(response)
   if 'Token' in jss and 'Id' in jss['Token']:
      token = jss['Token']['Id']
      expireTime = jss['Token']['ExpireTime']
      print("token = " + token)
      print("expireTime = " + str(expireTime))
except Exception as e:
   print(e)
   
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Note: The 'nls' library is part of Alibaba Cloud Speech SDK.
# You need to download and install it separately.
# Refer to https://help.aliyun.com/document_detail/450255.html for installation and token acquisition.
# For this agent, we assume Ali_voice_app_key and Ali_voice_token are directly available in settings.txt.

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest

class AliTTSSynthesizer:
    def __init__(self, appkey, access_id, access_key, url="wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1"):
        self.__appkey = appkey
        self.__access_id = access_id
        self.__access_key = access_key
        self.__url = url
        self.__token = self._get_sts_token()
        self.__url = url
        self.__f = None
        self.__completed = threading.Event()
        self.__error = False
        self.__audio_data = []
        self.__f = None
        self.__completed = threading.Event()
        self.__error = False
        self.__audio_data = []
        logging.info(f"AliTTSSynthesizer initialized with appkey: {appkey[:4]}..., access_id: {access_id[:4]}..., access_key: {access_key[:4]}...")

    def _get_sts_token(self):
        try:
            client = AcsClient(
                self.__access_id,
                self.__access_key,
                "cn-shanghai"  # You might want to make this configurable
            )
            request = CommonRequest()
            request.set_method('POST')
            request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
            request.set_version('2019-02-28')
            request.set_action_name('CreateToken')

            response = client.do_action_with_exception(request)
            jss = json.loads(response)
            if 'Token' in jss and 'Id' in jss['Token']:
                token = jss['Token']['Id']
                expireTime = jss['Token']['ExpireTime']
                logging.info(f"Successfully obtained STS Token. Expires at: {expireTime}")
                return token
            else:
                logging.error(f"Failed to get STS Token: {jss}")
                return None
        except Exception as e:
            logging.error(f"Error getting STS Token: {e}")
            return None

    def __on_metainfo(self, message, *args):
        logging.info(f"TTS metainfo received: {message}")

    def __on_error(self, message, *args):
        logging.error(f"TTS Error: {message}")
        self.__error = True
        self.__completed.set()

    def __on_close(self, *args):
        logging.info(f"TTS connection closed. Args: {args}")
        if self.__f:
            try:
                self.__f.close()
                logging.info(f"Output file closed successfully.")
            except Exception as e:
                logging.error(f"Error closing file: {e}")
        self.__completed.set()

    def __on_data(self, data, *args):
        if self.__f:
            try:
                self.__f.write(data)
                logging.debug(f"Received and wrote {len(data)} bytes of audio data.")
            except Exception as e:
                logging.error(f"Error writing data to file: {e}")
                self.__error = True
                self.__completed.set()

    def __on_completed(self, message, *args):
        logging.info(f"TTS synthesis completed. Message: {message}")
        self.__completed.set()

    def synthesize(self, text, output_file, voice="xiaoyun", aformat="mp3", sample_rate=16000, volume=50, speech_rate=0, pitch_rate=0, enable_subtitle=False):
        """
        Synthesizes text to speech using Alibaba Cloud TTS.

        Args:
            text (str): The text to synthesize.
            output_file (str): The path to save the synthesized audio file (e.g., "output.mp3").
            voice (str, optional): The voice to use. Defaults to "xiaoyun".
            aformat (str, optional): Audio format (e.g., "mp3", "wav", "pcm"). Defaults to "mp3".
            sample_rate (int, optional): Audio sample rate. Defaults to 16000.
            volume (int, optional): Volume (0-100). Defaults to 50.
            speech_rate (int, optional): Speech rate (-500 to 500). Defaults to 0.
            pitch_rate (int, optional): Pitch rate (-500 to 500). Defaults to 0.
            enable_subtitle (bool, optional): Whether to enable subtitle (timestamp) generation. Defaults to False.

        Returns:
            bool: True if synthesis was successful, False otherwise.
        """
        logging.info(f"Attempting to synthesize text to speech: '{text}' to '{output_file}'")
        try:
            self.__f = open(output_file, "wb")
            logging.info(f"Successfully opened output file {output_file} for writing.")
        except IOError as e:
            logging.error(f"Error opening output file {output_file}: {e}")
            return False

        self.__completed.clear()
        self.__error = False
        logging.info(f"Starting synthesis for text: '{text[:50]}...' to file: {output_file}")

        tts = nls.NlsSpeechSynthesizer(
            url=self.__url,
            token=self.__token,
            appkey=self.__appkey,
            on_metainfo=self.__on_metainfo,
            on_data=self.__on_data,
            on_completed=self.__on_completed,
            on_error=self.__on_error,
            on_close=self.__on_close
        )

        ex_params = {}
        if enable_subtitle:
            ex_params['enable_subtitle'] = True

        try:
            tts.start(
                text=text,
                voice=voice,
                aformat=aformat,
                sample_rate=sample_rate,
                volume=volume,
                speech_rate=speech_rate,
                pitch_rate=pitch_rate,
                ex=ex_params if ex_params else None
            )
            logging.info(f"Waiting for synthesis to complete with timeout: 60 seconds.")
            self.__completed.wait(timeout=60) # Wait for synthesis to complete, with a timeout
            if not self.__completed.is_set():
                logging.warning(f"TTS synthesis timed out after 60 seconds.")
        except Exception as e:
            logging.error(f"TTS synthesis failed during start or wait: {e}")
            self.__error = True
        finally:
            logging.info(f"Shutting down NLS speech synthesizer.")
            tts.shutdown()
            if self.__f and not self.__f.closed:
                self.__f.close()
                logging.info(f"Output file explicitly closed in finally block.")
            self.__f = None
            logging.info(f"Synthesis process finished. Error status: {self.__error}")

        file_size = 0
        if os.path.exists(output_file):
            file_size = os.path.getsize(output_file)
        logging.info(f"Synthesized audio file size: {file_size} bytes.")
        if file_size == 0:
            logging.warning(f"Synthesized audio file {output_file} is empty. This might indicate an issue with the TTS service or data writing.")
        return not self.__error

def get_ali_keys_from_settings():
    # Assuming settings.txt is in the parent directory of 'tools'
    settings_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'settings.txt')
    logging.info(f"Attempting to read settings from {settings_path}")
    try:
        with open(settings_path, 'r', encoding='utf-8') as f:
            settings = json.load(f)
            app_key = settings.get("Ali_voice_app_key")
            access_id = settings.get("Ali_voice_access_id")
            access_key = settings.get("Ali_voice_access_key")
            if not app_key:
                logging.warning("Ali_voice_app_key not found in settings.txt.")
            if not access_id:
                logging.warning("Ali_voice_access_id not found in settings.txt.")
            if not access_key:
                logging.warning("Ali_voice_access_key not found in settings.txt.")
            return app_key, access_id, access_key
    except FileNotFoundError:
        logging.error(f"Error: settings.txt not found at {settings_path}")
        return None, None, None
    except json.JSONDecodeError:
        logging.error(f"Error: Could not decode JSON from settings.txt at {settings_path}")
        return None, None, None
    except Exception as e:
        logging.error(f"An unexpected error occurred while reading settings.txt: {e}")
        return None, None, None

if __name__ == "__main__":
    nls.enableTrace(True)
    app_key, access_id, access_key = get_ali_keys_from_settings()

    if not app_key or not access_id or not access_key:
        logging.error("Ali_voice_app_key, Ali_voice_access_id, or Ali_voice_access_key not found in settings.txt. Please configure them.")
    else:
        synthesizer = AliTTSSynthesizer(appkey=app_key, access_id=access_id, access_key=access_key)

        # Example 1: Basic synthesis
        text_to_synthesize_1 = "你好，这是一个测试语音合成。欢迎使用阿里云智能语音服务。"
        output_audio_file_1 = "output_tts_test_1.mp3"
        logging.info(f"--- Running Example 1 ---")
        logging.info(f"Synthesizing: '{text_to_synthesize_1}' to '{output_audio_file_1}'")
        success_1 = synthesizer.synthesize(text_to_synthesize_1, output_audio_file_1)
        if success_1:
            logging.info(f"Speech synthesis completed successfully. Audio saved to {output_audio_file_1}")
        else:
            logging.error("Speech synthesis failed for Example 1.")

        # Example 2: Different voice and WAV format
        text_to_synthesize_2 = "今天天气真好，适合出去走走。"
        output_audio_file_2 = "output_tts_test_2.wav"
        logging.info(f"--- Running Example 2 ---")
        logging.info(f"Synthesizing: '{text_to_synthesize_2}' to '{output_audio_file_2}' with voice 'ruoxi' and WAV format")
        success_2 = synthesizer.synthesize(text_to_synthesize_2, output_audio_file_2, voice="ruoxi", aformat="wav", speech_rate=100)
        if success_2:
            logging.info(f"Speech synthesis completed successfully. Audio saved to {output_audio_file_2}")
        else:
            logging.error("Speech synthesis failed for Example 2.")

        # Example 3: With subtitle enabled (if supported by your NLS configuration)
        text_to_synthesize_3 = "开启字幕功能，体验更佳。"
        output_audio_file_3 = "output_tts_test_3.mp3"
        logging.info(f"--- Running Example 3 ---")
        logging.info(f"Synthesizing: '{text_to_synthesize_3}' to '{output_audio_file_3}' with subtitle enabled")
        success_3 = synthesizer.synthesize(text_to_synthesize_3, output_audio_file_3, enable_subtitle=True)
        if success_3:
            logging.info(f"Speech synthesis completed successfully. Audio saved to {output_audio_file_3}")
        else:
            logging.error("Speech synthesis failed for Example 3. Subtitle feature might require specific NLS configuration.")
